package edu.unc.comp410.colemangeer.checkoutdemo;

import static java.lang.System.out;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;

import edu.unc.comp410.colemangeer.model.ISellable;
import edu.unc.comp410.colemangeer.model.Product;
import edu.unc.comp410.colemangeer.model.ProductCategory;
import edu.unc.comp410.colemangeer.model.constraints.IConstraint;
import edu.unc.comp410.colemangeer.model.object.PersistentObject;

/**
 *  A Product for sale.
 * @author ccoleman
 * 
 * ---The price of any product is >= $1.00 and <= $100,000.00
 */
public class Product extends PersistentObject implements IConstraint, ISellable {
	/**
	 * Persistent object data fields
	 */
	// ID is handled by the superclass
	private final String productName;
	private final Double price;
	private final Set<ProductCategory> productCategories;
	private static final String SEP = "|"; // Field separator in String
	private static final String REGEX_SEP = "\\" + SEP;
	private static final String CAT_SEP = ","; // separator in the DB category field
	private static final String REGEX_CAT_SEP = CAT_SEP;
	private static final int NUM_FIELDS = 3; //TODO: why is this 3? shouldn't it be 4?  we are adding 1 to this down below, why?
	
	private static Logger log = Logger.getLogger(Product.class);
	/**
	 * Discount and tax rule(?) fields
	 * TODO: add these
	 */
	
	//TODO: make public interface for persistent fields
	
	/**
	 * public constructors
	 * 
	 * TODO: all params are required
	 */
	public Product(Integer id, String productName, Double price, Set<ProductCategory> categories) {
		
		super(id);
		
		if (productName == null || price == null || categories == null)
			throw new NullPointerException();
		
		if (price < Double.valueOf(1) || price > Double.valueOf(100000)) {
			throw new IllegalArgumentException();
		} 
			
		this.productName = productName;
		this.price = price;
		this.productCategories = categories;
	}

	/**
	 * Getters and Setters
	 */
	public String getProductName() {
		return productName;
	}

	public Double getPrice() {
		return price;
	}
	
	public String getName(){
		return productName;
	}
	
	public Integer getProductID(){
		return getId();
	}
	
	/**
	 * Convert a String representation into a Customer
	 */
	public static Product string2Object(String str) {
		out.println("str = " + str);
		String[] field = str.split(REGEX_SEP);
		//System.out.println("field.length is: *" + field.length + "*");
		//TODO: why do we add the getnumberofdatafields90 to num_fields???
		if (PersistentObject.getNumberOfDataFields() + NUM_FIELDS != field.length)
			throw new IllegalArgumentException();
		
		Integer theProdId = Integer.parseInt(field[0]);
		String theName = field[1];
		//out.println("field[1] = " + field[1]);
		
		Double thePrice = Double.parseDouble(field[2]);
		Set<ProductCategory> theCategory = new HashSet<ProductCategory>();
		
		//make ProductCategories out of the words in the category field
		String[] catField = field[3].split(REGEX_CAT_SEP);
		if ( catField.length < 1 )
			throw new IllegalArgumentException();
		
		//*orange* this is a stupid way of doing this, maybe I should fix it
		//TODO: possibly fix this
		for( String i: catField ){
			ProductCategory currentCat=null;
			
			if( i.equals("Magical") ){
				currentCat = ProductCategory.MAGICAL;
			}
			if( i.equals("Software") ){
				currentCat = ProductCategory.SOFTWARE;
			}
			if( i.equals("Book") ){
				currentCat = ProductCategory.BOOK;
			}
			if( i.equals("Weapon") ){
				currentCat = ProductCategory.WEAPON;
			}
			if( i.equals("Misc") ){
				currentCat = ProductCategory.MISC;
			}
			
			theCategory.add(currentCat);
		} //end for loop

		return new Product(theProdId, theName, thePrice, theCategory);
	}//end string2Object() method
	
	/** method to convert dollars (double) into cents (Integer)
	 * 
	 */
	
	// let's not do this
	public static Integer dollarsToCents( double theDollars ){
		double tempDollars = theDollars * 100;
		Integer result = (int)tempDollars;
		return result;
	}
	
	public Set<ProductCategory> getProductCategories() {
		return productCategories;
	}
	
	/**
	 *  return price + tax - discounts
	 */
	public Double getComputedPrice(){
		//TODO: implement this method properly
		return new Double(getPrice());
	}
	
	/**
	 * @return comma seperated list of this product's
	 * product categories
	 */
	public String getCategoryString(){
		
		StringBuilder result = new StringBuilder();
		boolean needsComma = false;
		
		for (ProductCategory c : productCategories){
			
			if (needsComma){
				result.append(", ");
			}
			else{
				needsComma = true;
			}
			
			result.append(c.toString());
		}
		return result.toString();
	}

	// returning List of products jsut like CatalogItem does
	// conforming to the ISellable interface

	public List<Product> getAllProducts() {
		ArrayList<Product> products = new ArrayList<Product>();
		products.add(this);
		return products; // TODO: return immutable copy instead
	}
	/* (non-Javadoc)
	 * @see edu.unc.comp410.colemangeer.model.object.MutableObject#clone()
	 */
	@Override
	public Object clone() throws CloneNotSupportedException {
		return new Product(getId(),getProductName(),getPrice(), getProductCategories());
	}

	/* (non-Javadoc)
	 * @see edu.unc.comp410.colemangeer.model.object.MutableObject#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (!(obj instanceof Product))
			return false;
		Product compareProduct = (Product) obj;
		
		return  this.getId().equals(compareProduct.getId())
		&& this.getProductName().equals(compareProduct.getProductName())
		&& this.getPrice().equals(compareProduct.getPrice())
		&& this.getProductCategories().equals(compareProduct.getProductCategories());
			
	}

	/* (non-Javadoc)
	 * @see edu.unc.comp410.colemangeer.model.object.MutableObject#hashCode()
	 */
	@Override
	public int hashCode() {
		int result = 17;
		result = (int) (31 * result + this.price);
		result = 31 * result + this.getId().intValue();
		result = 31 * result + this.getProductName().hashCode();
		result = 31 * result + this.getProductCategories().hashCode();
		return result;
	}

	/* (non-Javadoc)
	 * @see edu.unc.comp410.colemangeer.model.object.MutableObject#toString()
	 */
	@Override
	public String toString() {

		StringBuilder result = new StringBuilder(getId());
		result.append("|").append(getProductName())
		.append("|").append(getPrice())
		.append("|").append(getCategoryString()).append("|");
		
		return result.toString();
	}

	/* (non-Javadoc)
	 * @see edu.unc.comp410.colemangeer.model.constraints.IConstraint#getConstraintName()
	 */
	@Override
	public String getConstraintName() {
		// TODO Auto-generated method stub
		return null;
	}

	/* (non-Javadoc)
	 * @see edu.unc.comp410.colemangeer.model.constraints.IConstraint#isLegal(java.lang.Object)
	 */
	@Override
	public boolean isLegal(Object theObject) {
		// TODO Auto-generated method stub
		return false;
	}

	/* (non-Javadoc)
	 * @see edu.unc.comp410.colemangeer.model.constraints.IConstraint#validate(java.lang.Object)
	 */
	@Override
	public void validate(Object theObject) throws IllegalStateException {
		// TODO Auto-generated method stub

	}
}
